#ifndef COMPONENTCONSTUCTIONHELPER_H
#define COMPONENTCONSTUCTIONHELPER_H
#include "StompedReality/Core.h"
#include "StompedReality/Core/GameAccess.h"
#include "StompedReality/Core/IGame.h"
#include "StompedReality/Core/Memory/ObjectPoolManager.h"
#include "StompedReality/Core/TypeSystem/TypeSystem.h"
#include <assert.h>
#include <functional>
#include <string.h>
namespace StompedReality
{
namespace Graphics
{
class RenderFunction;
}
namespace components
{
class RenderInfoComponent;
}
namespace Core
{

class ComponentConstuctionHelper : public StompedReality::GameAccess {
 private:

  typedef std::vector<StompedReality::Core::Component*> ComponentList;
  JsonPTR m_JsonPtr;
  unsigned m_CurrentIDX;
  StompedReality::components::RenderInfoComponent* m_RenderComponent;
  ComponentList m_ComponentList;
  int FindCmpByName( std::string name );

 public:

  ComponentConstuctionHelper ( JsonPTR ptr );
  ~ComponentConstuctionHelper ( );

  void CreateComponents ( );

  void AddRenderFunction ( StompedReality::Graphics::RenderFunction* function );

  void Finish ( );

  Json::Value GetCurrentJsonValue( );
  bool IsStaticRenderable( );

  StompedReality::ID GetRenderInfoID( );

  template <typename TYPE>
  std::function< TYPE( )> CreateGetterDelegate ( std::string cmpName, std::string field );

  template <typename TYPE>
  std::function< TYPE( )> CreateGetterDelegateDeref ( std::string jsonField, std::string field );

  template <typename TYPE>
  std::function< void ( TYPE )> CreateSetterDelegate ( std::string cmpName, std::string field );

  template <typename TYPE>
  std::function< void ( TYPE )> CreateSetterDelegateDeref ( std::string jsonField, std::string field );

  template <typename TYPE>
  StompedReality::ValueDelegate<TYPE> CreateValueDelegate ( std::string cmpName, std::string field );

  template <typename TYPE>
  StompedReality::ValueDelegate<TYPE> CreateValueDelegateDeref ( std::string jsonField, std::string field );

};

template <typename TYPE>
std::function< TYPE ( ) > ComponentConstuctionHelper::CreateGetterDelegate ( std::string cmpName, std::string field )
{
  int idx = this->FindCmpByName( cmpName );
  assert ( idx != -1 );
  return this->m_Game->getComponentSystem( )->CreateGetterDelegate<TYPE>( this->m_ComponentList[idx]->GetType( ),
                                                                          this->m_ComponentList[idx]->GetID( ),
                                                                          field.c_str( ));
}

template <typename TYPE>
std::function< TYPE ( ) > ComponentConstuctionHelper::CreateGetterDelegateDeref ( std::string jsonField,
                                                                                  std::string field )
{
  return this->CreateGetterDelegate<TYPE>( this->GetCurrentJsonValue( ).get( jsonField, "" ).asString( ),
                                           field );
}

template <typename TYPE>
std::function< void ( TYPE ) > ComponentConstuctionHelper::CreateSetterDelegate ( std::string cmpName,
                                                                                  std::string field )
{
  int idx = this->FindCmpByName( cmpName );
  assert ( idx != -1 );
  return this->m_Game->getComponentSystem( )->CreateSetterDelegate<TYPE>( this->m_ComponentList[idx]->GetType( ),
                                                                          this->m_ComponentList[idx]->GetID( ),
                                                                          field.c_str( ));
}

template <typename TYPE>
std::function< void ( TYPE ) > ComponentConstuctionHelper::CreateSetterDelegateDeref ( std::string jsonField,
                                                                                       std::string field )
{
  return this->CreateSetterDelegate<TYPE>( this->GetCurrentJsonValue( ).get( jsonField, "" ).asString( ),
                                           field );
}

template <typename TYPE>
StompedReality::ValueDelegate<TYPE> ComponentConstuctionHelper::CreateValueDelegate ( std::string cmpName,
                                                                                      std::string field )
{
  int idx = this->FindCmpByName( cmpName );
  assert ( idx != -1 );
  return this->m_Game->getComponentSystem( )->CreateValueDelegate<TYPE>( this->m_ComponentList[idx]->GetType( ),
                                                                         this->m_ComponentList[idx]->GetID( ),
                                                                         field.c_str( ));
}

template <typename TYPE>
StompedReality::ValueDelegate<TYPE> ComponentConstuctionHelper::CreateValueDelegateDeref ( std::string jsonField,
                                                                                           std::string field )
{
  return this->CreateValueDelegate<TYPE>( this->GetCurrentJsonValue( ).get( jsonField, "" ).asString( ),
                                          field );
}

}

}

#endif // COMPONENTCONSTUCTIONHELPER_H
